package com.katesoft.scale4j.web.services;

import com.katesoft.scale4j.log.Logger;
import com.katesoft.scale4j.log.LogFactory;
import com.katesoft.scale4j.web.model.Role;
import com.katesoft.scale4j.web.model.User;
import com.katesoft.scale4j.web.model.UserLocale;
import com.katesoft.scale4j.web.security.ISecurityRoles;
import com.katesoft.scale4j.web.support.WebappDaoSupport;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.dao.DataAccessException;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;

/**
 * Contains common functionality around user/roles/locale stuff.
 *
 * @author kate2007
 */
@Transactional(rollbackFor = Exception.class)
public class UserRoleService extends WebappDaoSupport implements IUserRoleService
{
    private Logger logger = LogFactory.getLogger(UserRoleService.class);
    private UserDetailsService userDetailsService;
    private IUserNotificationService userNotificationService;

    @Transactional(readOnly = true)
    @Override
    public Collection<Role> findAllRoles()
    {
        return getLocalHibernateTemplate().loadAll(Role.class, true);
    }

    @Transactional(readOnly = true)
    @Override
    public Collection<UserLocale> findAllLocales()
    {
        return getLocalHibernateTemplate().loadAll(UserLocale.class, true);
    }

    @Secured(ISecurityRoles.IS_AUTHENTICATED_ANONYMOUSLY)
    @Override
    @Transactional(readOnly = true)
    public String requestNewPassword(final String userName)
    {
        User user;
        try {
            user = (User) userDetailsService.loadUserByUsername(userName);
        }
        catch (UsernameNotFoundException e) {
            logger.error("User with username[%s] does not exist", userName);
            throw e;
        }
        String newPassword = RandomStringUtils.randomAlphanumeric(15);
        logger.debug("generated new password[%s] for username[%s]", newPassword, userName);
        user.setPassword(DigestUtils.shaHex(newPassword));
        if (userNotificationService != null) { userNotificationService.notifyNewPassword(newPassword, user); }
        return newPassword;
    }

    @Override
    public void updatePassword(String newPassword,
                               String username)
    {
        final User user = loadUser(username);
        user.setPassword(newPassword);
        getLocalHibernateTemplate().update(user);
        getLocalHibernateTemplate().flush();
        if (userNotificationService != null) { userNotificationService.notifyPasswordUpdated(newPassword, user); }
    }

    @Transactional(readOnly = true)
    @Override
    public UserLocale getUserPreferableLocale(String username)
    {
        User user = loadUser(username);
        return user.getUserPreferences() == null ? null : user.getUserPreferences().getLocale();
    }

    @Override
    public void updateUserPreferableLocale(String newLocale,
                                           String username)
    {
        UserLocale locale = loadLocale(newLocale);
        User user = loadUser(username);
        user.getUserPreferences().setLocale(locale);
        getLocalHibernateTemplate().update(user);
        getLocalHibernateTemplate().flush();
        if (userNotificationService != null) {userNotificationService.notifyUserPreferableLocaleUpdated(newLocale, user);}
    }

    @Transactional(readOnly = true)
    @Override
    public User loadUserByUsername(final String username) throws UsernameNotFoundException, DataAccessException
    {
        return (User) userDetailsService.loadUserByUsername(username);
    }

    @Transactional(readOnly = true)
    @Override
    public Collection<User> search(String queryString)
    {
        return search(queryString, User.class, new String[]{User.PROP_LOGIN, User.PROP_EMAIL});
    }

    @Override
    @Transactional(readOnly = true)
    public UserLocale loadLocale(String code)
    {
        return super.loadLocale(code);
    }

    public void deleteUser(final User user)
    {
        getLocalHibernateTemplate().delete(user);
        getLocalHibernateTemplate().flush();
    }

    public void saveOrUpdateUser(User user)
    {
        user.getAccount();
        user.getPerson();
        if (user.getRoles() == null || user.getRoles().isEmpty()) { user.getRoles().add(loadRoleByName(ISecurityRoles.ROLE_USER)); }
        getLocalHibernateTemplate().saveOrUpdate(user);
        getLocalHibernateTemplate().flush();
    }
    // ***********************************************************************
    // ************************* (getters+setters) ***************************
    // ***********************************************************************

    @Required
    @Autowired
    public void setUserDetailsService(UserDetailsService userDetailsService)
    {
        this.userDetailsService = userDetailsService;
    }

    public void setUserNotificationService(IUserNotificationService userNotificationService)
    {
        this.userNotificationService = userNotificationService;
    }
}
